using Admin.NET.Core.Entity;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Exceptions;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Dysmsapi.Model.V20170525;
using Furion.SpecificationDocument;
using Lazy.Captcha.Core;
using Microsoft.Extensions.Caching.Memory;
using Org.BouncyCastle.Tls;
using ClientException = Aliyun.Acs.Core.Exceptions.ClientException;

namespace Admin.NET.Core.Service;

/// <summary>
/// 系统登录授权服务
/// </summary>
[ApiDescriptionSettings(Order = 500)]
public class SysAuthService : IDynamicApiController, ITransient
{
    private readonly UserManager _userManager;
    private readonly SqlSugarRepository<SysUser> _sysUserRep;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly SysMenuService _sysMenuService;
    private readonly SysOnlineUserService _sysOnlineUserService;
    private readonly SysConfigService _sysConfigService;
    private readonly IMemoryCache _cache;
    private readonly ICaptcha _captcha;
    private readonly SysUserRoleService _sysUserRoleService;
    private readonly SqlSugarRepository<SysPhoneCode> _sysPhoneCode;

    public SysAuthService(UserManager userManager,
        SqlSugarRepository<SysUser> sysUserRep,
        IHttpContextAccessor httpContextAccessor,
        SysMenuService sysMenuService,
        SysOnlineUserService sysOnlineUserService,
        SysConfigService sysConfigService,
        IMemoryCache cache,
        ICaptcha captcha,
        SysUserRoleService sysUserRoleService, SqlSugarRepository<SysPhoneCode> sysPhoneCode)
    {
        _userManager = userManager;
        _sysUserRep = sysUserRep;
        _httpContextAccessor = httpContextAccessor;
        _sysMenuService = sysMenuService;
        _sysOnlineUserService = sysOnlineUserService;
        _sysConfigService = sysConfigService;
        _cache = cache;
        _captcha = captcha;
        _captcha = captcha;
        _sysUserRoleService = sysUserRoleService;
        _sysPhoneCode = sysPhoneCode;
    }
    /// <summary>
    /// 短信发送（通用方法）
    /// </summary>
    /// <param name="phoneNumber">手机号码</param>
    /// <param name="Type">类型：0登录；1修改密码</param>
    /// <returns></returns>
    [HttpPost("/SendSmsTY")]
    [AllowAnonymous]
    [SuppressMonitor]
    public bool SendSmsTY(string phoneNumber, int Type)
    {
        IClientProfile profile = DefaultProfile.GetProfile("cn-hangzhou", "LTAI5tDCKnkiQTBDvHQGe79S", "oMIN2Lgg8eMv20RWMHFaxni1IkGHQm");
        DefaultAcsClient client = new DefaultAcsClient(profile);
        SendSmsRequest request = new SendSmsRequest();
        request.PhoneNumbers = phoneNumber;
        var code = GenerateCode(6);//随机生成6位验证码
        request.SignName = "生久科技";// 短信签名，需要在阿里云控制台申请
        if (Type == 0)
            request.TemplateCode = "SMS_249100185"; // 短信模板Code，需要在阿里云控制台申请(登录验证)
        else
            request.TemplateCode = "SMS_249100185 "; // 短信模板Code，需要在阿里云控制台申请(修改密码)
        //request.TemplateParam = "{\"code\":\"123456\"}";
        request.TemplateParam = $"{{\"code\":\"{code}\"}}";
        try
        {
            //发送短信
            SendSmsResponse response = client.GetAcsResponse(request);
            //保存数据

            SysPhoneCode phonecode = new SysPhoneCode();
            phonecode.Id = Guid.NewGuid().ToString("N");
            phonecode.Phone = phoneNumber;
            phonecode.Code = code;
            phonecode.CreateTime = DateTime.Now;
            phonecode.Type = Type;
            _sysPhoneCode.InsertAsync(phonecode);

            // 处理响应结果
            return true;
        }
        catch (ServerException ex)
        {
            throw Oops.Oh($"异常：{ex.Message}");
            // 处理异常
        }
        catch (ClientException ex)
        {
            throw Oops.Oh($"异常：{ex.Message}");
            // 处理异常
        }
    }
    /// <summary>
    /// 根据手机号验证码登录系统
    /// </summary>
    /// <param name="input"></param>
    /// <remarks>用户名/密码：vben/123456</remarks>
    /// <returns></returns>
    [HttpPost("/loginbyphone")]
    [AllowAnonymous]
    [SuppressMonitor]
    public async Task<LoginOutput> loginbyphone([Required] LoginInputByPhone input)
    {
        // var encryptPasswod = MD5Encryption.Encrypt(input.Password); // 加密密码
        // 判断用户手机号
        var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg)
            .FirstAsync(u => u.Phone.Equals(input.Phone));
        _ = user ?? throw Oops.Oh(ErrorCodeEnum.D1000);
        // 判断用户名验证码
        if (user != null)
        {
            var nowtime = DateTime.Now.AddMinutes(-5);//验证码五分钟内有效
            var Phonecodelist = await _sysPhoneCode.AsQueryable()
    .Where(u => u.Phone == input.Phone && u.Code == input.Code && u.CreateTime >= nowtime && u.Type == 0).ToListAsync();
            if (Phonecodelist.Count <= 0)
                throw Oops.Oh("验证码有误");

        }




        // 账号是否被冻结
        if (user.Status == StatusEnum.Disable)
            throw Oops.Oh(ErrorCodeEnum.D1017);

        // 租户是否被禁用
        var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
        if (tenant != null && tenant.Status == StatusEnum.Disable)
            throw Oops.Oh(ErrorCodeEnum.Z1003);


        // 单用户登录
        await _sysOnlineUserService.SignleLogin(user.Id);

        var tokenExpire = await _sysConfigService.GetTokenExpire();
        var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();

        // 生成Token令牌
        var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
        {
            { ClaimConst.UserId, user.Id },
            { ClaimConst.TenantId, user.TenantId },
            { ClaimConst.Account, user.Account },
            { ClaimConst.RealName, user.RealName },
            { ClaimConst.AccountType, user.AccountType },
            { ClaimConst.OrgId, user.OrgId },
            { ClaimConst.OrgName, user.SysOrg?.Name },
            { ClaimConst.Ent,input.Ent},
            { ClaimConst.Site,input.Site},
            { ClaimConst.Workstation,input.Workstation},
        }, tokenExpire);

        // 生成刷新Token令牌
        var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);

        // 设置响应报文头
        _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);

        // Swagger Knife4UI-AfterScript登录脚本
        // ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']);

        return new LoginOutput
        {
            AccessToken = accessToken,
            RefreshToken = refreshToken
        };
    }
    private static string GenerateCode(int length)
    {
        const string chars = "0123456789";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, length)
          .Select(s => s[random.Next(s.Length)]).ToArray());
    }

    /// <summary>
    /// 登录系统
    /// </summary>
    /// <param name="input"></param>
    /// <remarks>用户名/密码：superadmin/123456</remarks>
    /// <returns></returns>
    [AllowAnonymous]
    [DisplayName("登录系统")]
    public async Task<LoginOutput> Login([Required] LoginInput input)
    {
        //// 可以根据域名获取具体租户
        //var host = _httpContextAccessor.HttpContext.Request.Host;

        // 是否开启验证码
        if (await _sysConfigService.GetConfigValue<bool>(CommonConst.SysCaptcha))
        {
            // 判断验证码
            if (!_captcha.Validate(input.CodeId.ToString(), input.Code))
                throw Oops.Oh(ErrorCodeEnum.D0008);
        }

        // 账号是否存在
        var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).Filter(null, true).FirstAsync(u => u.Account.Equals(input.Account));
        _ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);

        // 账号是否被冻结
        if (user.Status == StatusEnum.Disable)
            throw Oops.Oh(ErrorCodeEnum.D1017);

        // 租户是否被禁用
        var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
        if (tenant != null && tenant.Status == StatusEnum.Disable)
            throw Oops.Oh(ErrorCodeEnum.Z1003);

        // 密码是否正确
        if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
        {
            if (user.Password != MD5Encryption.Encrypt(input.Password))
                throw Oops.Oh(ErrorCodeEnum.D1000);
        }
        else
        {
            if (CryptogramUtil.Decrypt(user.Password) != input.Password)
                throw Oops.Oh(ErrorCodeEnum.D1000);
        }

        // 单用户登录
        await _sysOnlineUserService.SignleLogin(user.Id);

        var tokenExpire = await _sysConfigService.GetTokenExpire();
        var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();

        // 生成Token令牌
        var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
        {
            { ClaimConst.UserId, user.Id },
            { ClaimConst.TenantId, user.TenantId },
            { ClaimConst.Account, user.Account },
            { ClaimConst.RealName, user.RealName },
            { ClaimConst.AccountType, user.AccountType },
            { ClaimConst.OrgId, user.OrgId },
            { ClaimConst.OrgName, user.SysOrg?.Name },
            { ClaimConst.Ent,input.Ent},
            { ClaimConst.Site,input.Site},
            { ClaimConst.Workstation,input.Workstation},
        }, tokenExpire);

        // 生成刷新Token令牌
        var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);

        // 设置响应报文头
        _httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);

        // Swagger Knife4UI-AfterScript登录脚本
        // ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']);

        return new LoginOutput
        {
            AccessToken = accessToken,
            RefreshToken = refreshToken
        };
    }

    /// <summary>
    /// 获取登录账号
    /// </summary>
    /// <returns></returns>
    [DisplayName("登录系统")]
    public async Task<LoginUserOutput> GetUserInfo()
    {
        var user = await _sysUserRep.GetFirstAsync(u => u.Id == _userManager.UserId);
        if (user == null)
            throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);

        // 获取机构
        var org = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysOrg>>().GetFirstAsync(u => u.Id == user.OrgId);
        // 获取职位
        var pos = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysPos>>().GetFirstAsync(u => u.Id == user.PosId);
        // 获取拥有按钮权限集合
        var buttons = await _sysMenuService.GetOwnBtnPermList();
        // 角色信息
        var roles = await _sysUserRoleService.GetUserRoleList(user.Id);
        
        return new LoginUserOutput
        {
            Account = user.Account,
            RealName = user.RealName,
            Avatar = user.Avatar,
            Address = user.Address,
            Signature = user.Signature,
            OrgId = user.OrgId,
            OrgName = org?.Name,
            PosName = pos?.Name,
            Buttons = buttons,
            RoleInfo = roles.Select(u => new LoginRole
            {
                Name = u.Name,
                Code = u.Code
            }).ToList(),
        };
    }

    /// <summary>
    /// 获取刷新Token
    /// </summary>
    /// <param name="accessToken"></param>
    /// <returns></returns>
    [DisplayName("获取刷新Token")]
    public string GetRefreshToken(string accessToken)
    {
        var refreshTokenExpire = _sysConfigService.GetRefreshTokenExpire().GetAwaiter().GetResult();
        return JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
    }

    /// <summary>
    /// 退出系统
    /// </summary>
    [DisplayName("退出系统")]
    public void Logout()
    {
        if (string.IsNullOrWhiteSpace(_userManager.Account))
            throw Oops.Oh(ErrorCodeEnum.D1011);

        _httpContextAccessor.HttpContext.SignoutToSwagger();
    }

    /// <summary>
    /// 获取登录配置
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [SuppressMonitor]
    [DisplayName("获取登录配置")]
    public async Task<dynamic> GetLoginConfig()
    {
        var secondVerEnabled = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysSecondVer);
        var captchaEnabled = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysCaptcha);
        return new { SecondVerEnabled = secondVerEnabled, CaptchaEnabled = captchaEnabled };
    }

    /// <summary>
    /// 获取用户配置
    /// </summary>
    /// <returns></returns>
    [SuppressMonitor]
    [DisplayName("获取用户配置")]
    public async Task<dynamic> GetUserConfig()
    {
        //返回用户和通用配置
        var watermarkEnabled = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysWatermark);
        return new { WatermarkEnabled = watermarkEnabled };
    }

    /// <summary>
    /// 获取验证码
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [SuppressMonitor]
    [DisplayName("获取验证码")]
    public dynamic GetCaptcha()
    {
        var codeId = YitIdHelper.NextId();
        var captcha = _captcha.Generate(codeId.ToString());
        return new { Id = codeId, Img = captcha.Base64 };
    }

    /// <summary>
    /// swagger登录检查
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("/api/swagger/checkUrl"), NonUnify]
    [DisplayName("swagger登录检查")]
    public int SwaggerCheckUrl()
    {
        return _cache.Get<bool>(CacheConst.SwaggerLogin) ? 200 : 401;
    }

    /// <summary>
    /// swagger登录提交
    /// </summary>
    /// <param name="auth"></param>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("/api/swagger/submitUrl"), NonUnify]
    [DisplayName("swagger登录提交")]
    public int SwaggerSubmitUrl([FromForm] SpecificationAuth auth)
    {
        var userName = App.GetConfig<string>("SpecificationDocumentSettings:LoginInfo:UserName");
        var password = App.GetConfig<string>("SpecificationDocumentSettings:LoginInfo:Password");
        if (auth.UserName == userName && auth.Password == password)
        {
            _cache.Set<bool>(CacheConst.SwaggerLogin, true);
            return 200;
        }
        return 401;
    }
}